import { Box3, Color, DoubleSide, Group, Material, MathUtils, Matrix4, Mesh, Object3D, PerspectiveCamera, Raycaster, UniformsUtils, Vector3 } from "three";
import Config from "../../application/constants/Config";
import { App } from "../../application";
import Events from "../../application/constants/Events";
import {LRUCache, PriorityQueue, Tile, TilesRenderer, GLTFCesiumRTCExtension, GLTFExtensionsPlugin} from "3d-tiles-renderer";
import { Point } from "../../renderExtension/types/Point";
import GeoUtils from "../../utils/GeoUtils";
import Const from "../../application/constants/Const";
import Helper from "../../utils/Helper";
import MaterialAdapter from "../../renderExtension/Material/MaterialAdapter";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import MeshUtil from "../../renderExtension/utils/MeshUtil";
import {CustomTilesRender} from "./CustomTilesRender";
import GPSUtils from "../../utils/GPSUtils";

/**
 * 3dtiles对象
 */
class Tiles3d extends Group {
    public options: any;
    private app: App;
    private virturalCameraList: Array<PerspectiveCamera>;
    // private virturalCamera: PerspectiveCamera; //在笛卡尔椭球坐标系统中的虚拟相机
    // private virturalCamera2: PerspectiveCamera;
    private tilesRenderer: any;
    private rootTilePosition: Vector3;
    private distanceFromGround: number;
    private rootJson;
    private halfWidth: number;

    /**
     * 构造函数
     * @param options 加载3dtiles数据需要用到的参数
     * @param options.url 3dtiles数据的url
     * @param options.refinement 通过该参数控制对加载数据精细程度的控制。这个值越小，加载越粗糙的数据；值越大，加载越精细的数据。但是如果值设置的太大，会对性能造成影响
     * @param options.loadRange 加载范围。默认可以不用设置，引擎内部会计算加载的范围，但是为了数据预加载，可以把这个值设置的比较大。如果这个值太大，加载的范围会很大，会对性能造成影响
     * @param options.z 调节3dtiles数据的高度。如果元素数据的高度是10，这个z值为100，那么3dtiles在地图上的高度就是110
     * @param options.minSize 缓存瓦片的最小值
     * @param options.maxSize 缓存瓦片的最大值 
     * @param options.isDoubleSide 是否开启双面渲染，默认是不开启 
     * @param options.isSupportTransparent 是否开启透明度，默认是不开启
     * @param options.geoSystem 数据使用的坐标系，默认是4978，也可以是3857 isOpenAdditionalCamera
     * @param options.isOpenAdditionalCamera 是否添加预加载的额外相机，默认开启  
     * @param options.additionCameraFov 额外相机的fov，默认是120  maxJobs
     * @param options.maxJobs 优先级队列中每次执行下载解析任务的最大数量，默认是6
     * @example 
     * let tiles3d = new GE.Tiles3d({
           url: '/examples/resources/3dtiles/goodguizhou/tileset.json',
           location: [120.12677193212092, 30.26499469319121, 10],
           isLocate: true,
           maxSize: 2600,
           isOpenAdditionalCamera: true,
           additionCameraFov: 30,
           maxJobs: 60,
           isSupportTransparent: false,
           isDoubleSide: false,
           geoSystem: '4978',
       });
       app.add(tiles3d);
     */
    constructor(options) {
        super();
        for (var key in Config.Tile3d) {
            if (!options.hasOwnProperty(key)) { //如果options中不存在该属性，则使用Config.Tile3d中的值
            //   console.log(key + ": " + obj[key]);
                options[key] = Config.Tile3d[key];
            }
        }
        this.options = options;
        this['canNotSelect'] = this.options['canNotSelect'];
        // this.options = Object.assign(Config.Tile3d, options);
        let testPoint =  GeoUtils.threedtilePointToWGS(  -1300341.46563933, 5309228.01609976, 3277211.38517791 );
        console.log(testPoint);
        // testPoint.z += this.options.z;
        // testPoint.z += -1200;
        // console.log( GeoUtils.WGSTothreedtilePoint(testPoint));

        this.app = App.getInstance();
        this.virturalCameraList = new Array<PerspectiveCamera>();

        if (this.options.geoSystem == '4978' || !this.options.geoSystem) { //椭球坐标系
            let cameraPosition = this.app.camera.position;
            let cameraPositonWgs = new Point(cameraPosition.x, cameraPosition.y, cameraPosition.z, Const.EPSGType.EPSGWeb);
            let cameraPositonCartesian = GeoUtils.WGSTothreedtilePoint(cameraPositonWgs);

            let cameraLookTarget = this.app.camera.lookAtTarget;
            let cameraLookTargetWgs = new Point(cameraLookTarget.x, cameraLookTarget.y, cameraLookTarget.z, Const.EPSGType.EPSGWeb);
            let cameraLookTargetCartesian = GeoUtils.WGSTothreedtilePoint(cameraLookTargetWgs);

            let aspect = this.app.three.camera.aspect;
            let fov = this.app.three.camera.fov;// + 2;
            let near = this.app.three.camera.near;
            let far = this.app.three.camera.far;
            let virturalCamera = new PerspectiveCamera(fov, aspect, near, far); //this.app.three.camera.clone()
            virturalCamera.up.set(0, 0, 1);
            virturalCamera.position.copy(cameraPositonCartesian);
            virturalCamera.lookAt(cameraLookTargetCartesian);
            // this.app.add(virturalCamera);
            this.virturalCameraList.push(virturalCamera);

            if(this.options.isOpenAdditionalCamera == true){
                let additionCameraFov = this.options.additionCameraFov;
                let virturalCamera2 = new PerspectiveCamera(additionCameraFov, aspect, near, far);
                virturalCamera2.up.set(0, 0, 1);
                virturalCamera2.position.copy(cameraPositonCartesian);
                virturalCamera2.lookAt(cameraLookTargetCartesian);
                // this.app.add(virturalCamera2);
                this.virturalCameraList.push(virturalCamera2);
                // virturalCamera['isOpenAdditionalCamera'] = true;
            }
        } else { //web墨卡托坐标系
            let originCamera = this.app.three.camera;
            this.virturalCameraList.push(originCamera);

            if(this.options.isOpenAdditionalCamera == true){
                let virturalCamera = this.app.three.camera.clone();
                virturalCamera.fov = this.options.additionCameraFov;
                virturalCamera.up.set(0, 0, 1);
                virturalCamera.position.copy(originCamera.position);
                virturalCamera.lookAt(this.app.camera.lookAtTarget);
                // this.app.add(virturalCamera);
                this.virturalCameraList.push(virturalCamera);
            }
        }

        // let debounceCameraEvent = Helper.debounce2(this.updateVirturalCameraEvent, 500, false);
        // this.app.on(Events.CameraChange, debounceCameraEvent, this);

        this.app.on(Events.wheelChange, this.updateCameraEvent, this);
        this.app.on(Events.MapDragEnd, this.updateCameraEvent, this);
        // this.app.on(Events.MapDragStart, this.closeFbxSwitcher, this);
        // this.app.on(Events.MapDragEnd, this.openFbxSwitcher, this);
        this.load();
    }

    // private openFbxSwitcher() {
    //     this.tilesRenderer.openFbxSwitcher = true;
    // }

    // private closeFbxSwitcher() {
    //     this.tilesRenderer.openFbxSwitcher = false;
    // }

    private isMemoryExplosion() {
        if (window.performance && window.performance['memory']) {
            const memory = window.performance['memory'];
            let memoryInfo = {
                usedJSHeapSize: memory.usedJSHeapSize,
                totalJSHeapSize: memory.totalJSHeapSize,
                jsHeapSizeLimit: memory.jsHeapSizeLimit
            };

            //如果totalJSHeapSize超过jsHeapSizeLimit的80%, 就返回true
            if (memoryInfo.usedJSHeapSize >= memoryInfo.jsHeapSizeLimit * 0.6) {
                return true;
            }
            return false;
        } else {
            return false;
        }
    }

    private updateCameraEvent() {

        let cameraPosition = this.app.camera.position;
        let cameraLookTarget = this.app.camera.lookAtTarget;

        if (this.options.geoSystem == '4978' || !this.options.geoSystem) { //椭球坐标系，默认就是椭球坐标   
            let cameraPositonWgs = new Point(cameraPosition.x, cameraPosition.y, cameraPosition.z, Const.EPSGType.EPSGWeb);
            let cameraPositonCartesian = GeoUtils.WGSTothreedtilePoint(cameraPositonWgs);

            let cameraLookTargetWgs = new Point(cameraLookTarget.x, cameraLookTarget.y, cameraLookTarget.z, Const.EPSGType.EPSGWeb);
            let cameraLookTargetCartesian = GeoUtils.WGSTothreedtilePoint(cameraLookTargetWgs);

            this.virturalCameraList.forEach(camera => {
                camera.position.copy(cameraPositonCartesian);
                camera.lookAt(cameraLookTargetCartesian);
                camera.updateMatrix();
				camera.updateMatrixWorld();
            });
        } else if (this.options.geoSystem && this.options.geoSystem == '3857') { //web墨卡托坐标系
            this.virturalCameraList.forEach(camera => {
                camera.position.copy(cameraPosition);
                camera.lookAt(cameraLookTarget);
                camera.updateMatrix();
				camera.updateMatrixWorld();
            });
        }

        this.calculateScreenError(this.distanceFromGround);
    }

    private load() {
        if (!this.tilesRenderer) {
            this.initRender();
        }

        this.animate();
        this.app.on(Events.Render, this.animate, this);
    }
    private initRender() {
        this.tilesRenderer = new CustomTilesRender(this.options);//this.options.url, this.options.z
        this.tilesRenderer.errorTarget = 0;//this.options.errorTarget; //100; //
        if (this.options.radiusScale) {
            this.tilesRenderer.radiusScale = this.options.radiusScale;
        }
        this.tilesRenderer.errorThreshold = this.options.errorThreshold; //50000;
        this.tilesRenderer.maxDepth = this.options.maxDepth;
        this.tilesRenderer.loadSiblings = this.options.loadSiblings;
        this.tilesRenderer.displayActiveTiles = this.options.displayActiveTiles;
        // this.tilesRenderer.autoDisableRendererCulling  = this.options.autoDisableRendererCulling;
        this.tilesRenderer.optimizeRaycast = this.options.optimizeRaycast;

        let lruPriorityCallback = this.tilesRenderer.lruCache.unloadPriorityCallback;
        this.tilesRenderer.lruCache.unloadPercent = this.options.unloadPercent;
        this.tilesRenderer.lruCache.unloadPriorityCallback = lruPriorityCallback; //( itemA, itemB ) => itemA.priority - itemB.priority;
        this.tilesRenderer.lruCache.computeMemoryUsageCallback = this.getTileMemory;
        this.tilesRenderer.lruCache.minSize = this.options.minSize;
        this.tilesRenderer.lruCache.maxSize = this.options.maxSize;
        this.tilesRenderer.lruCache.maxByteSize  = this.options.maxByteSize;
        this.tilesRenderer.lruCache.minByteSize   = this.options.minByteSize;

        let downloadPriorityCallback = this.tilesRenderer.downloadQueue.priorityCallback;
        // this.tilesRenderer.downloadQueue  = new PriorityQueue();
        this.tilesRenderer.downloadQueue.maxJobs = this.options.maxJobs;
        this.tilesRenderer.downloadQueue.priorityCallback = downloadPriorityCallback; //( itemA, itemB ) => itemA.priority - itemB.priority;

        let parsePriorityCallback = this.tilesRenderer.parseQueue.priorityCallback;
        // this.tilesRenderer.parseQueue  = new PriorityQueue();
        this.tilesRenderer.parseQueue.maxJobs = this.options.maxJobs;
        this.tilesRenderer.parseQueue.priorityCallback = parsePriorityCallback; //( itemA, itemB ) => itemA.priority - itemB.priority;
        // this.tilesRenderer.registerPlugin( new ReorientationPlugin() );
        // this.tilesRenderer.registerPlugin( new GLTFExtensionsPlugin( { metadata: true } ) ); //GLTFExtensionsPlugin
        
        let self = this;

        self.virturalCameraList.forEach(Camera => {
            self.tilesRenderer.setCamera(Camera);
            self.tilesRenderer.setResolutionFromRenderer(Camera, self.app.three.renderer);
        });

        let isRootJson = true;
        let gltfUpAxis: string = 'Y';
        // let modelUpAxis: string = 'Y';
        this.tilesRenderer.onDispose = function () {

        };

        this.tilesRenderer.onTileVisibilityChange = function (model: Object3D, tile: Tile, visible: boolean) {

        };

        this.tilesRenderer.forEachLoadedModel(function (scene, tile) {

        });

        this.tilesRenderer.addEventListener( 'load-tile-set', function (json) {
            if (isRootJson) {
                self.rootJson = json.tileSet;
                gltfUpAxis = json.tileSet.asset.gltfUpAxis || 'Y';
                // modelUpAxis = json.asset.modelUpAxis || 'Y';

                let transform = json.tileSet.root.transform;
                if (!transform) {
                    transform = [
                        1, 0, 0, 0,
                        0, 1, 0, 0,
                        0, 0, 1, 0,
                        0, 0, 0, 1
                    ];
                }

                if (self.options.geoSystem == '4978' || !self.options.geoSystem) { //椭球坐标
                    let wsgPoint = GeoUtils.threedtilePointToWGS(transform[12], transform[13], transform[14]);
                    // if (wsgPoint && self.options.z) {
                    //     wsgPoint.z += self.options.z;
                    //     let newThreedTilePoint = GeoUtils.WGSTothreedtilePoint(wsgPoint);
                    //     transform[12] = newThreedTilePoint.x;
                    //     transform[13] = newThreedTilePoint.y;
                    //     transform[14] = newThreedTilePoint.z;
                    // }
                    
                    if (wsgPoint) {
                        self.rootTilePosition = wsgPoint.toEPSGWeb();
                    } else {
                        self.rootTilePosition = new Vector3();
                    }
                }else{
                    // if(self.options.z){
                    //     transform[14] += (self.options.z);
                    // }
                    if (self.options.geoSystem == '3857') { //web墨卡托坐标
                        self.rootTilePosition = new Vector3(transform[12], transform[13], transform[14]);
                    } else if (self.options.geoSystem == '4326') { //84坐标
                        let webPoint = GeoUtils.P84toWeb(transform[12], transform[13]);
                        self.rootTilePosition = new Vector3(webPoint.x, webPoint.y, transform[14]);
                    }
                } 
                let locationPosition :Vector3 = self.rootTilePosition.clone();
                let range: {startPoint: Point, endPoint: Point} = {startPoint: null, endPoint: null};
                // self.virturalCameraList.forEach(Camera => {
                //     self.tilesRenderer.setCamera(Camera);
                //     self.tilesRenderer.setResolutionFromRenderer(Camera, self.app.three.renderer);
                // });

                let boundingVolume = json.tileSet.root.boundingVolume;
                if (boundingVolume.box) {
                    // if (modelUpAxis == 'Z') { //gltf模型的z轴朝上
                    //     self.distanceFromGround = self.rootTilePosition.z + boundingVolume.box[2] + Math.abs(boundingVolume.box[11]); //模型的离地高度
                    //     self.halfWidth = Math.max(boundingVolume.box[3], boundingVolume.box[7]) / 10;
                    // }else if (modelUpAxis == 'Y') { //gltf模型的Y轴朝上
                    //     self.distanceFromGround = self.rootTilePosition.z + boundingVolume.box[1] + Math.abs(boundingVolume.box[7]); //模型的离地高度
                    //     self.halfWidth = Math.max(boundingVolume.box[3], boundingVolume.box[11]) / 10;
                    // }
                    //boundingVolume.box[11] = 10;
                    self.distanceFromGround = self.rootTilePosition.z + boundingVolume.box[2] + Math.abs(boundingVolume.box[11]); //模型的离地高度
                    self.halfWidth = Math.max(boundingVolume.box[3], boundingVolume.box[7]) / 10;

                    locationPosition.add(new Vector3(boundingVolume.box[0], boundingVolume.box[1], boundingVolume.box[2]));
                    range.startPoint = new Point(locationPosition.x-boundingVolume.box[3], locationPosition.y-boundingVolume.box[4], self.distanceFromGround, Const.EPSGType.EPSGWeb);
                    range.endPoint = new Point(locationPosition.x+boundingVolume.box[6], locationPosition.y+boundingVolume.box[7], self.distanceFromGround, Const.EPSGType.EPSGWeb);
                } else if (boundingVolume.sphere) {
                    self.distanceFromGround = self.rootTilePosition.z + boundingVolume.sphere[2] + Math.abs(boundingVolume.sphere[3]); //模型的离地高度
                    self.halfWidth = boundingVolume.sphere[3] / 10;

                    locationPosition.add(new Vector3(boundingVolume.sphere[0], boundingVolume.sphere[1], boundingVolume.sphere[2]));
                    range.startPoint = new Point(locationPosition.x-boundingVolume.sphere[3], locationPosition.y-boundingVolume.sphere[4], self.distanceFromGround, Const.EPSGType.EPSGWeb);
                    range.endPoint = new Point(locationPosition.x+boundingVolume.sphere[3], locationPosition.y+boundingVolume.sphere[4], self.distanceFromGround, Const.EPSGType.EPSGWeb);
                } else if (boundingVolume.region) {
                    self.distanceFromGround = self.rootTilePosition.z + (Math.abs(boundingVolume.region[5] - boundingVolume.region[4])); //模型的离地高度
                    self.halfWidth = 1000;

                    range.startPoint = new Point(boundingVolume.region[0], boundingVolume.region[1], self.distanceFromGround, Const.EPSGType.EPSG84).toEPSGWeb();
                    range.endPoint = new Point(boundingVolume.region[2], boundingVolume.region[1], self.distanceFromGround, Const.EPSGType.EPSG84).toEPSGWeb();
                }

                // if (self.options.z) {
                //     self.distanceFromGround += self.options.z;
                // }

                self.tilesRenderer.errorThreshold = Math.max(Math.abs(self.halfWidth), self.options.loadRange);
                self.calculateScreenError(self.distanceFromGround);

                if(self.options.isLocate){
                    self.app.camera.setVisualScope(range, function(){
                        self.updateCameraEvent();
                    });
                }
                
            }
            isRootJson = false;

            if (self.options.callback) {
                self.options.callback();
                self.options.callback = null;
            }
        });

        this.tilesRenderer.addEventListener( 'load-model', function (modelData) {
            let model:Object3D = modelData.scene;
            let tile: Tile = modelData.tile;
            model['url'] = tile.content.uri;

            let modelPositon = model.position;
            let originxy = [modelPositon.x, modelPositon.y];
            if (self.options.geoSystem == '4978' || !self.options.geoSystem) { //椭球坐标
                //在CustomTilesRender.preprocessNode()方法中已经考虑到了各个瓦片的地理坐标，因此这里得到的wsgPoint就在当前地图的地理坐标系类，后边转换为平面坐标的时候不用再考虑地图的不同地理坐标系，可以直接投影
                let wsgPoint = GeoUtils.threedtilePointToWGS(modelPositon.x, modelPositon.y, modelPositon.z);
                if (wsgPoint) {
                    let modelScale = (1 / Math.cos(MathUtils.degToRad(wsgPoint.y))) + 0.003; //缩放瓦片，避免出现缝隙
                    model.scale.set(modelScale, 1, modelScale);
                    let webMapPoint = wsgPoint.toEPSGWeb2();
                    
                    modelPositon.copy(webMapPoint); //设置瓦片的位置
                    model.updateMatrix();
                }
            } else if (self.options.geoSystem == '3857') { //web墨卡托坐标
                //
            } else if (self.options.geoSystem == '4326') { //84坐标
                // let webPoint = GeoUtils.P84toWeb(transform[12], transform[13]);
                // self.rootTilePosition = new Vector3(webPoint.x, webPoint.y, transform[14]);
            }


            let rotationMatrix:Matrix4 = new Matrix4(); //旋转瓦片，使瓦片和底图平行
            // if(modelData.tile.content.uri.endsWith('.pnts')) //点云数据，目前点云数据无法解决在地图上不对齐的问题
            if (gltfUpAxis == 'Y') { //gltf模型的y轴朝上
                // upAdjustment.makeRotationAxis( X_AXIS, Math.PI / 2 );
                rotationMatrix.makeRotationX(Math.PI / 2); //绕x轴旋转90度
                model.setRotationFromMatrix(rotationMatrix);
            } else if (gltfUpAxis == 'Z') { //gltf模型的z轴朝上
                model.setRotationFromMatrix(rotationMatrix); //不用任何旋转
            } else if (gltfUpAxis == 'X') { //gltf模型的x轴朝上
                //upAdjustment.makeRotationAxis( Y_AXIS, - Math.PI / 2 );
                rotationMatrix.makeRotationY(-Math.PI / 2); //绕y轴旋转90度
                model.setRotationFromMatrix(rotationMatrix);
            }

            model.updateMatrix();
            
            self.setMaterial(model);
        });

        this.tilesRenderer.addEventListener( 'dispose-model', function (modelData) {
            MeshUtil.dispose(modelData.scene);
        });

        this.tilesRenderer.addEventListener( 'tile-visibility-change', function (modelData) {
            if(modelData.visible){
                let model:Object3D = modelData.scene;
                self.app.fireEvent(Events.AdjustModelHeight, model.parent); //通知其他模型根据这个3dtiles瓦片的数据调整高度
                self.app.fireEvent(Events.AddTile); 
            }
        })

        // if (this.options.z) {
        //     this.tilesRenderer.group.position.z = this.options.z;
        // }
        this.add(this.tilesRenderer.group);
        this.setDracoLoader(this.options.dracoGltfPath);
    }

    private setDracoLoader(dracoGltfPath) {
        if (!dracoGltfPath) {
            return;
        }
        const dracoLoader = new DRACOLoader();
        // dracoLoader.setDecoderPath( 'https://unpkg.com/three@0.123.0/examples/js/libs/draco/gltf/' );
        dracoLoader.setDecoderPath(dracoGltfPath);

        const loader = new GLTFLoader( this.tilesRenderer.manager );
        loader.setDRACOLoader( dracoLoader );
        loader.register( () => new GLTFCesiumRTCExtension() );
        this.tilesRenderer.manager.addHandler( /\.(gltf|glb)$/g, loader );
    }

    /**
     * 设置是否只加载最粗糙的数据
     * @param isOnlyLoadCoarse 是否只加载最粗糙的数据
     */
    public loadCoarseData(isOnlyLoadCoarse: boolean){
        if(this.tilesRenderer){
            this.tilesRenderer.isOnlyLoadCoarse = isOnlyLoadCoarse;
        }
    }

    private calculateScreenError(distanceFromGround) {
        if (!this.rootJson) {
            return;
        }
        // let verticalFov = this.app.three.camera.fov * this.app.three.camera.aspect;

        let distance = Math.abs(this.app.three.camera.position.z - distanceFromGround);
        let screenError;
        // let viewFrustumHeight = 2 * Math.abs(1  * distance * Math.tan( verticalFov/2 ));
        // let viewFrustumWidth = 2 * Math.abs(1 * distance * Math.tan(this.app.three.camera.fov / 2));// * distance;

        // if (distance < 0) {
        //     screenError = this.tilesRenderer.errorTarget;// / 2;
        // } else {
        if (this.options.refinement <= 0) {
            this.options.refinement = 1;
        }
        let refinement = this.options.refinement;
        let distanceError = distance * (1 / refinement);
        let geometricError = this.rootJson.geometricError;
        if (!geometricError) {
            geometricError = this.rootJson.root.geometricError;
        }
        if (!geometricError) {
            geometricError = 1;
        }
        let errorFactor1 = Math.max(Math.log(distanceError), 1);
        let errorFactor2 = Math.max(Math.log(distanceError * geometricError), 1);
        screenError = errorFactor1 * errorFactor2;
        // }

        // if (screenError < 10) {
        //     // viewFrustumWidth = 100; //2 * viewFrustumWidth; //

        //     if (screenError < 0) {
        //         screenError = 0;
        //     }
        // }
        screenError *= this.options.screenErrorFactor;
        if (screenError == 0) {
            screenError = this.options.screenErrorFactor;
        }
        this.tilesRenderer.errorTarget = screenError;
    }

    private setMaterial(model) { //开启双面渲染
        if (!this.options.isDoubleSide && !this.options.changeEmissive && !this.options.isSupportTransparent && !this.options.isReplaceMaterial && !this.options.isComputeBox) {
            return;
        }

        let self = this;
        Helper.traverseObject(model, function (Object) {
            if (Object.type == 'Mesh') {
                if(self.options.isComputeBox){
                    let modelBox = new Box3().setFromObject(model, true);
                    Object[Const.MapConst.meshBox] = modelBox;
                }
                
                if (Object.material.length > 1) {
                     let newMaterialArray = [];
                    Object.material.forEach(element => {
                        let newMaterial = MaterialAdapter.convertMaterial(element);

                         if (self.options.isDoubleSide) {
                            newMaterial.side = DoubleSide;
                        }

                        if (newMaterial.opacity != 1) {
                            newMaterial.transparent = true;
                        }

                        if (self.options.changeEmissive) {
                            self.setEmmisive(newMaterial);
                        }
                        newMaterialArray.push(newMaterial);
                    });
                    Object.material = newMaterialArray;
                } else {
                    Object.material = MaterialAdapter.convertMaterial(Object.material);
                    if (self.options.isDoubleSide) {
                        (Object.material as Material).side = DoubleSide;
                    }

                    if ((Object.material as Material).opacity != 1) {
                        (Object.material as Material).transparent = true;
                    }

                    if (self.options.changeEmissive) {
                        self.setEmmisive(Object.material);
                    }

                }
            }
            return true;
        });
    }

    private setEmmisive(material) {
        if (!material.emissive) {
            return;
        }
        material.emissive.set(1, 1, 1);
        material.emissiveIntensity = 1;
        material.emissiveMap = material.map;
    }

    private getScreenWidth(viewFrustumWidth: number, distance: number) {
        let position = this.app.three.camera.position.clone();
        position.z -= distance;

        let leftPositon = position.clone();
        leftPositon.x += viewFrustumWidth;

        let positionNdc = position.project(this.app.three.camera); //把三维点转换到归一化坐标
        let screenPoint = this.convertNdcToScreen(positionNdc);

        let leftPositionNdc = leftPositon.project(this.app.three.camera); //把三维点转换到归一化坐标
        let screenPoint2 = this.convertNdcToScreen(leftPositionNdc);

        let screenWidth = Math.abs(screenPoint.x - screenPoint2.x);
        return screenWidth;
    }

    private convertNdcToScreen(ndcPoint) {
        const screenX = (ndcPoint.x + 1) / 2 * window.outerWidth;
        const screenY = (-ndcPoint.y + 1) / 2 * window.outerHeight;
        return { x: screenX, y: screenY }
    }

    private animate() {
        // if(this.isMemoryExplosion()){
        //     console.log('内存即将超过上限，删除掉不在可视范围内的瓦片');
        //     this.tilesRenderer.lruCache.minSize = 0; //内存即将超过上限，删除掉不在可视范围内的瓦片
        //     this.tilesRenderer.lruCache.maxSize = 1000;
        // }
        this.rotation.set(0, 0, 0);
        this.updateMatrixWorld(true);

        if (this.virturalCameraList) {
            this.virturalCameraList.forEach(camera => {
                camera.updateMatrixWorld();
            });
        }

        // this.secondCadmera.updateMatrixWorld();
        this.tilesRenderer.update();
    }

    // Adjusts the three.js standard shader to include batchid highlight
    private batchIdHighlightShaderMixin(shader) {
        const newShader = { ...shader };
        newShader.uniforms = {
            highlightedBatchId: { value: - 1 },
            highlightColor: { value: new Color(0xFFC107).convertSRGBToLinear() },
            ...UniformsUtils.clone(shader.uniforms),
        };
        newShader.extensions = {
            derivatives: true,
        };
        newShader.lights = true;
        newShader.vertexShader =
            `
                attribute float _batchid;
                varying float batchid;
            ` +
            newShader.vertexShader.replace(
                /#include <uv_vertex>/,
                `
                #include <uv_vertex>
                batchid = _batchid;
                `
            );
        newShader.fragmentShader =
            `
                varying float batchid;
                uniform float highlightedBatchId;
                uniform vec3 highlightColor;
            ` +
            newShader.fragmentShader.replace(
                /#include <hotmap_fragment>/,
                `
                #include <hotmap_fragment>
                gl_FragColor = abs( batchid - highlightedBatchId ) < 0.0001 ?
                    vec4( highlightColor, gl_FragColor.a ) :
                    vec4( gl_FragColor.r, gl_FragColor.g, gl_FragColor.b, gl_FragColor.a );
                `
            );

        return newShader;
    }

    /**
     * 设置选中对象及其颜色
     * @param mesh 被选中的mesh族
     * @param batchid 被选中对象的batchid
     * @param color 高亮颜色
     */
    private setSelectColor(mesh, batchid, color) {
        mesh.material.uniforms.highlightedBatchId.value = batchid;
        mesh.material.uniforms.highlightColor.value = new Color(color).convertSRGBToLinear();
    }

    /**
     * 恢复原有颜色
     * @param mesh 需要恢复颜色的对象
     */
    private resetColor(mesh) {
        mesh.material.uniforms.highlightedBatchId.value = -1;
    }


    public dispose() {
        this.app.off(Events.Render, this.animate, this);
        this.tilesRenderer.dispose();
        // MeshUtil.dispose(this);

        if(this.parent){
            this.parent.remove(this);
        }

        let self = this;
        this.virturalCameraList.forEach(virturalCamera => {
            self.app.remove(virturalCamera);
        });
    }

    public getTileMemory(tile){
        if (tile && tile.cached) {
            return tile.cached.bytesUsed;
        } else {
            return null;
        }
    }
}
export { Tiles3d }